package com.obggtc.picture.controller;


import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.obggtc.picture.common.R;
import com.obggtc.picture.config.PathConfig;
import com.obggtc.picture.entity.MediaFile;
import com.obggtc.picture.service.MediaFileService;
import com.obggtc.picture.utils.CommonUtils;
import com.obggtc.picture.utils.StringTool;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;


@RestController
@RequestMapping("/image")
@CrossOrigin
@PreAuthorize("isAuthenticated()")
public class ImageController {

    private static final Logger log = LoggerFactory.getLogger(ImageController.class);

    @Autowired
    private PathConfig pathConfig;

    @Resource
    private CommonUtils commonUtils;
    
    @Autowired
    private MediaFileService mediaFileService;



    /**
     * 上传img
     *
     * @param file 文件
     * @return {@link JSONObject}
     */
    @SneakyThrows
    @PostMapping(value = "/uploadImg", consumes = {"multipart/form-data"})
    public R uploadImg(@RequestParam("file") MultipartFile file,
                       @RequestParam(value = "isPrint", defaultValue = "1") String isPrint,
                       @RequestParam(value = "email", required = false) String email,
                       @RequestParam(value = "title", required = false) String title,
                       @RequestParam(value = "description", required = false) String description,
                       @RequestParam(value = "tags", required = false) String tags,
                       @RequestParam(value = "originalFilename", required = false) String clientOriginalFilename,
                       HttpServletRequest request) {

        // 获取当前用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();

        // 1. 基本参数验证
        if (file.isEmpty()) {
            return R.failed("图片文件不能为空");
        }

        // 优先使用客户端传递的原始文件名，其次使用MultipartFile的文件名
        String originalFilename = clientOriginalFilename;
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            originalFilename = file.getOriginalFilename();
        }
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            return R.failed("文件名不能为空");
        }
        
        log.info("上传文件 - 客户端文件名: {}, MultipartFile文件名: {}, 最终使用: {}", 
                clientOriginalFilename, file.getOriginalFilename(), originalFilename);

        // 2. 文件类型验证 - 直接从文件扩展名判断
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
        String contentType = file.getContentType();
        
        // 验证是否为支持的图片格式
        if (!isValidImageExtension(fileExtension)) {
            return R.failed("不支持的图片格式: " + fileExtension + "，支持的格式: jpg, jpeg, png, gif, webp, bmp, svg");
        }
        
        // 如果ContentType为空，根据扩展名设置
        if (contentType == null || contentType.isEmpty()) {
            contentType = getContentTypeByExtension(fileExtension);
            log.info("根据文件扩展名 {} 设置ContentType为: {}", fileExtension, contentType);
        }
        
        log.info("文件验证通过 - 扩展名: {}, ContentType: {}", fileExtension, contentType);

        // 3. 生成文件ID和新文件名
        String fileId = "img_" + System.currentTimeMillis() + "_" + StringTool.getUUID();
        String fileExtensionWithDot = originalFilename.substring(originalFilename.lastIndexOf("."));
        String newFileName = fileId + fileExtensionWithDot;
        String tempFileName = newFileName + ".tmp"; // 临时文件名

        // 4. 确定保存路径
        File imageFile;
        File tempImageFile;
        File imageDir;
        String host;
        String filePath;
        String os = System.getProperty("os.name");
        
        if (os.toLowerCase().startsWith("win")) {
            host = pathConfig.getWinHost();
            imageFile = new File(pathConfig.getWinPath(), newFileName);
            tempImageFile = new File(pathConfig.getWinPath(), tempFileName);
            imageDir = new File(pathConfig.getWinPath());
            filePath = pathConfig.getWinPath();
        } else {
            host = pathConfig.getLinuxHost();
            imageFile = new File(pathConfig.getLinuxPath(), newFileName);
            tempImageFile = new File(pathConfig.getLinuxPath(), tempFileName);
            imageDir = new File(pathConfig.getLinuxPath());
            filePath = pathConfig.getLinuxPath();
        }

        // 5. 创建目录
        if (!imageDir.exists()) {
            boolean created = imageDir.mkdirs();
            if (!created) {
                log.error("创建图片目录失败: {}", imageDir.getAbsolutePath());
                return R.failed("创建图片目录失败");
            }
        }

        try {
            // 6. 保存文件
            log.info("开始保存文件 - 原始大小: {} bytes, 目标路径: {}", file.getSize(), imageFile.getAbsolutePath());
            
            // 检查文件是否为空
            if (file.isEmpty()) {
                log.error("上传的文件为空");
                return R.failed("上传的文件为空");
            }
            
            // 检查目标目录是否可写
            if (!imageDir.canWrite()) {
                log.error("目标目录不可写: {}", imageDir.getAbsolutePath());
                return R.failed("目标目录没有写权限");
            }
            
            // 使用更安全的文件保存方式 - 先写到临时文件，然后重命名
            try (InputStream inputStream = file.getInputStream();
                 FileOutputStream outputStream = new FileOutputStream(tempImageFile)) {
                
                byte[] buffer = new byte[8192]; // 8KB buffer
                int bytesRead;
                long totalBytesWritten = 0;
                
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                    totalBytesWritten += bytesRead;
                }
                
                outputStream.flush(); // 确保数据完全写入
                outputStream.getFD().sync(); // 强制同步到磁盘
                
                log.info("流式写入完成，总写入字节: {}", totalBytesWritten);
                
            } catch (IOException e) {
                log.error("文件保存过程中发生IO错误: {}", e.getMessage(), e);
                // 如果保存失败，删除可能的不完整临时文件
                if (tempImageFile.exists()) {
                    boolean deleted = tempImageFile.delete();
                    log.info("删除不完整临时文件: {}, 结果: {}", tempImageFile.getAbsolutePath(), deleted);
                }
                return R.failed("文件保存失败: " + e.getMessage());
            }
            
            // 原子操作：重命名临时文件为最终文件名
            if (!tempImageFile.renameTo(imageFile)) {
                log.error("重命名临时文件失败: {} -> {}", tempImageFile.getAbsolutePath(), imageFile.getAbsolutePath());
                // 清理临时文件
                if (tempImageFile.exists()) {
                    tempImageFile.delete();
                }
                return R.failed("文件保存失败：重命名操作失败");
            }
            
            log.info("文件原子操作完成: {} -> {}", tempImageFile.getName(), imageFile.getName());
            
            // 验证文件保存后的大小
            long savedFileSize = imageFile.length();
            log.info("图片文件保存成功 - 保存路径: {}, 原始大小: {} bytes, 保存后大小: {} bytes", 
                    imageFile.getAbsolutePath(), file.getSize(), savedFileSize);
            
            // 检查文件大小是否一致
            if (savedFileSize != file.getSize()) {
                log.warn("警告: 文件大小不一致! 原始: {} bytes, 保存后: {} bytes", file.getSize(), savedFileSize);
            }
            
            // 检查文件是否真的存在且可读
            if (!imageFile.exists() || !imageFile.canRead()) {
                log.error("保存的文件不存在或不可读: {}", imageFile.getAbsolutePath());
                return R.failed("文件保存失败");
            }
            
            // 验证图片文件格式是否正确
            try {
                // 检查文件头是否为有效的图片格式
                byte[] fileHeader = new byte[8];
                try (FileInputStream fis = new FileInputStream(imageFile)) {
                    int bytesRead = fis.read(fileHeader);
                    if (bytesRead > 0) {
                        String hexHeader = bytesToHex(fileHeader).toUpperCase();
                        log.info("文件头信息: {}", hexHeader);
                        
                        // 检查是否为常见图片格式
                        if (!isValidImageFormat(hexHeader)) {
                            log.warn("警告: 文件头不是有效的图片格式: {}", hexHeader);
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("无法验证图片格式: {}", e.getMessage());
            }

            // 7. 生成访问URL
            String fileUrl = host + "/static/img/" + newFileName;

            // 8. 保存到数据库
            MediaFile mediaFile = new MediaFile();
            mediaFile.setFileId(fileId);
            mediaFile.setFileType(MediaFile.FILE_TYPE_IMAGE);
            mediaFile.setOriginalFilename(originalFilename);
            mediaFile.setStoredFilename(newFileName);
            mediaFile.setFileSize(file.getSize());
            mediaFile.setFilePath(filePath);
            mediaFile.setFileUrl(fileUrl);
            mediaFile.setMimeType(contentType);
            mediaFile.setFileExtension(fileExtensionWithDot);
            mediaFile.setTitle(title != null ? title : originalFilename);
            mediaFile.setDescription(description);
            mediaFile.setTags(tags);
            mediaFile.setViewCount(0L);
            mediaFile.setDownloadCount(0L);
            mediaFile.setStatus(MediaFile.STATUS_NORMAL);
            mediaFile.setIsPublic(MediaFile.PRIVACY_PUBLIC);
            mediaFile.setUploader(username);
            mediaFile.setUploaderIp(getClientIpAddress(request));
            mediaFile.setCreateTime(LocalDateTime.now());
            mediaFile.setUploadTime(LocalDateTime.now());

            // 保存到数据库
            boolean saved = mediaFileService.saveMediaFile(mediaFile);
            if (!saved) {
                log.error("保存图片信息到数据库失败: {}", fileId);
                return R.failed("保存图片信息失败");
            }
            
            // 手动清除相关缓存，确保新上传的图片能立即在列表中显示
            mediaFileService.clearMediaFileCache(fileId);

            // 9. 处理打印逻辑（保留原有逻辑）
            if ("2".equals(isPrint)) {
                Map<String, Object> result = new HashMap<>();
                result.put("fileId", fileId);
                result.put("imgUrl", fileUrl);
                result.put("fileName", originalFilename);
                result.put("fileSize", file.getSize());
                
                List<String> list = commonUtils.get("imgUrl");
                list = CollUtil.isEmpty(list) ? new ArrayList<>() : list;
                list.add(fileUrl);
                commonUtils.set("imgUrl", list);
                
                // 有用户选择打印之后，设置缓存状态为1，表示待下载
                CommonUtils.status = "1";
                
                log.info("图片上传成功 - 用户: {}, 文件ID: {}, 文件名: {}", username, fileId, originalFilename);
                
                return R.ok(result, "图片上传成功");
            }

            // 10. 返回标准结果
            Map<String, Object> result = new HashMap<>();
            result.put("fileId", fileId);
            result.put("imgUrl", fileUrl);
            result.put("fileName", originalFilename);
            result.put("fileSize", file.getSize());
            result.put("uploadTime", System.currentTimeMillis());

            log.info("图片上传成功 - 用户: {}, 文件ID: {}, 文件名: {}", username, fileId, originalFilename);

            return R.ok(result, "图片上传成功");

        } catch (Exception e) {
            log.error("图片上传失败", e);
            return R.failed("图片上传失败: " + e.getMessage());
        }
    }


    @GetMapping("/getStatus")
    public R getStatus(){
      String res =   CommonUtils.status ;
        return R.ok(res);
    }

    //返回背景图片id和签名图片url给pc端
    @GetMapping("/get")
    public R imageIdAndUrl(){
        //pc端调用接口拿到信息之后，设置缓存状态为0，表示已下载
        CommonUtils.status = "0";

        List<String> url =  commonUtils.containsKey("imgUrl") ?   commonUtils.get("imgUrl") : new ArrayList<>();
        List<String> urlList = new ArrayList<>(url);
        //pc端拿到图片之后清空，重新累计
        commonUtils.clear("imgUrl");
       //String imgId =  commonUtils.containsKey("backGroudImgId") ? (String) commonUtils.get("backGroudImgId") : null;
        Map<String,Object> result = new HashMap<>();
        result.put("imgUrl",urlList);
        //result.put("backGroudImgId",imgId);

        return R.ok(result);
    }

    /**
     * 获取用户的图片列表
     * @param page 页码（默认1）
     * @param size 每页大小（默认10）
     * @return 图片列表
     */
    @GetMapping("/list")
    public R getUserImages(@RequestParam(value = "page", defaultValue = "1") int page,
                          @RequestParam(value = "size", defaultValue = "10") int size) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();

        try {
            log.info("开始获取用户图片列表 - username: {}, page: {}, size: {}", username, page, size);
            
            // 先统计总数
            long totalCount = mediaFileService.countUserMediaFiles(username, MediaFile.FILE_TYPE_IMAGE);
            log.info("用户图片总数 - username: {}, totalCount: {}", username, totalCount);
            
            IPage<MediaFile> result = mediaFileService.getUserMediaFiles(username, MediaFile.FILE_TYPE_IMAGE, page, size);
            
            Map<String, Object> response = new HashMap<>();
            response.put("images", result.getRecords());
            response.put("total", result.getTotal());
            response.put("page", result.getCurrent());
            response.put("size", result.getSize());
            response.put("totalPages", result.getPages());

            log.info("返回图片列表响应 - username: {}, total: {}, records: {}", username, result.getTotal(), result.getRecords().size());
            return R.ok(response, "获取图片列表成功");
        } catch (Exception e) {
            log.error("获取用户图片列表失败", e);
            return R.failed("获取图片列表失败");
        }
    }

    /**
     * 获取图片详细信息
     * @param fileId 图片文件ID
     * @return 图片详细信息
     */
    @GetMapping("/{fileId}")
    public R getImageDetail(@PathVariable String fileId) {
        try {
            MediaFile mediaFile = mediaFileService.getMediaFileByFileId(fileId);
            
            if (mediaFile == null || !(MediaFile.FILE_TYPE_IMAGE == mediaFile.getFileType())) {
                return R.failed("图片不存在");
            }

            // 增加观看次数
            long viewCount = mediaFileService.incrementViewCount(fileId);
            mediaFile.setViewCount(viewCount);

            return R.ok(mediaFile, "获取图片详情成功");
        } catch (Exception e) {
            log.error("获取图片详情失败: {}", fileId, e);
            return R.failed("获取图片详情失败");
        }
    }

    /**
     * 删除图片
     * @param fileId 图片文件ID
     * @return 删除结果
     */
    @DeleteMapping("/{fileId}")
    public R deleteImage(@PathVariable String fileId) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();

        try {
            boolean success = mediaFileService.deleteMediaFile(fileId, username);
            if (success) {
                return R.ok("图片删除成功");
            } else {
                return R.failed("图片删除失败");
            }
        } catch (Exception e) {
            log.error("删除图片失败: {}", fileId, e);
            return R.failed("删除图片失败");
        }
    }

    /**
     * 获取最近上传的图片
     * @param count 返回数量（默认10）
     * @return 最近上传的图片列表
     */
    @GetMapping("/recent")
    public R getRecentImages(@RequestParam(value = "count", defaultValue = "10") int count) {
        try {
            List<MediaFile> recentImages = mediaFileService.getRecentMediaFiles(MediaFile.FILE_TYPE_IMAGE, count);
            return R.ok(recentImages, "获取最近上传图片成功");
        } catch (Exception e) {
            log.error("获取最近上传图片失败", e);
            return R.failed("获取最近上传图片失败");
        }
    }

    /**
     * 根据标签搜索图片
     * @param tag 标签
     * @param page 页码（默认1）
     * @param size 每页大小（默认10）
     * @return 搜索结果
     */
    @GetMapping("/search/tag")
    public R searchImagesByTag(@RequestParam("tag") String tag,
                              @RequestParam(value = "page", defaultValue = "1") int page,
                              @RequestParam(value = "size", defaultValue = "10") int size) {
        try {
            IPage<MediaFile> result = mediaFileService.getMediaFilesByTag(tag, MediaFile.FILE_TYPE_IMAGE, page, size);
            
            Map<String, Object> response = new HashMap<>();
            response.put("images", result.getRecords());
            response.put("total", result.getTotal());
            response.put("page", result.getCurrent());
            response.put("size", result.getSize());
            response.put("tag", tag);

            return R.ok(response, "搜索图片成功");
        } catch (Exception e) {
            log.error("搜索图片失败", e);
            return R.failed("搜索图片失败");
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        return request.getRemoteAddr();
    }

    /**
     * 验证是否为支持的图片扩展名
     * @param fileExtension 文件扩展名
     * @return 是否为有效的图片格式
     */
    private boolean isValidImageExtension(String fileExtension) {
        String ext = fileExtension.toLowerCase();
        return "jpg".equals(ext) || "jpeg".equals(ext) || "png".equals(ext) || 
               "gif".equals(ext) || "webp".equals(ext) || "bmp".equals(ext) || "svg".equals(ext);
    }

    /**
     * 根据文件扩展名推断ContentType
     * @param fileExtension 文件扩展名
     * @return ContentType
     */
    private String getContentTypeByExtension(String fileExtension) {
        switch (fileExtension.toLowerCase()) {
            case "jpg":
            case "jpeg":
                return "image/jpeg";
            case "png":
                return "image/png";
            case "gif":
                return "image/gif";
            case "webp":
                return "image/webp";
            case "bmp":
                return "image/bmp";
            case "svg":
                return "image/svg+xml";
            default:
                return "image/jpeg"; // 默认为jpeg
        }
    }
    
    /**
     * 将字节数组转换为十六进制字符串
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString();
    }
    
    /**
     * 检查文件头是否为有效的图片格式
     * @param hexHeader 十六进制文件头
     * @return 是否为有效图片格式
     */
    private boolean isValidImageFormat(String hexHeader) {
        // JPEG: FF D8 FF
        if (hexHeader.startsWith("FFD8FF")) {
            return true;
        }
        // PNG: 89 50 4E 47
        if (hexHeader.startsWith("89504E47")) {
            return true;
        }
        // GIF: 47 49 46 38
        if (hexHeader.startsWith("47494638")) {
            return true;
        }
        // BMP: 42 4D
        if (hexHeader.startsWith("424D")) {
            return true;
        }
        // WebP: 52 49 46 46 (RIFF) 然后是 57 45 42 50 (WEBP)
        if (hexHeader.startsWith("52494646")) {
            return true;
        }
        
        return false;
    }

}
